package com.zhouqinuan.spring.cloud.develop.framework.base.util;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.StringUtils;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class DateTimeUtil {

	public static String DATE_FORMAT_SIMPLE = "yyyyMMdd";
	public static String DATE_FORMAT_SLASH = "yyyy/MM/dd";
	public static String DATE_FORMAT = "yyyy-MM-dd";
	public static String DATE_FORMAT2 = "yyyy年MM月dd日";

	public static String DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";

	public static String DATETIME_FORMAT2 = "yyyy-MM-dd HH:mm";

	public static Date parseDate(String str) {
		return parse(str, DATE_FORMAT);
	}

	public static Date parseDateTime(String str) {
		return parse(str, DATETIME_FORMAT);
	}

	public static Date parseDateTimeWithNull(String str) {
		try {
			if (StringUtils.isBlank(str)) {
				return null;
			}
			return parse(str, DATETIME_FORMAT);
		} catch (Exception ex) {
			log.error("解析时间错误: {} {}", str, ex);
		}

		return null;
	}

	public static Date parse(String str, String format) {
		try {
			return new SimpleDateFormat(format).parse(str);
		} catch (ParseException e) {
			throw new RuntimeException(e);
		}
	}

	public static String format(Date date, String format) {
		if (date == null)
			return "";
		return new SimpleDateFormat(format).format(date);
	}

	public static String formatDate(Date date) {
		return format(date, DATE_FORMAT);
	}

	public static String formatDate(Long time) {
		return format(new Date(time), DATE_FORMAT);
	}

	public static String formatDateTime(Date date) {

		return format(date, DATETIME_FORMAT);
	}

	public static String formatDate() {
		return format(new Date(), DATE_FORMAT);
	}

	public static String formatDateTime() {
		return format(new Date(), DATETIME_FORMAT);
	}

	public static Date date235959(Date date) {
		return date(date, 23, 59, 59);
	}

	public static Date date(Date date, int h, int m, int s) {
		Calendar d = Calendar.getInstance();
		d.setTime(date);
		d.set(Calendar.HOUR_OF_DAY, h);
		d.set(Calendar.MINUTE, m);
		d.set(Calendar.SECOND, s);
		d.set(Calendar.MILLISECOND, 0);
		return d.getTime();
	}

	public static boolean compareSameDay(Date date1, Date date2) {
		return formatDate(date1).equals(formatDate(date2));
	}

	public static Date date000000(Date date) {
		return date(date, 0, 0, 0);
	}

	public static String translate(Date date, String format) {
		if (date == null)
			return "";
		long now = System.currentTimeMillis();
		long s = now - date.getTime();
		if (s < 0) {
			return format(date, format);
		}
		if (s < 1000L * 60) {
			return "刚刚";
		}
		if (s < 60 * 1000L * 60) {
			return (s / (1000L * 60)) + "分钟前";
		}
		if (s < 24 * 1000L * 3600) {
			return (s / (1000L * 3600)) + "小时前";
		}
		if (s < 7 * 24 * 1000L * 3600) {
			return (s / (24 * 1000L * 3600)) + "天前";
		}

		return format(date, format);
	}

	/**
	 * 获取当前在星期几
	 *
	 * @param dt
	 *            时间
	 * @return 星期几, 星期一为1,星期天为7
	 */
	public static int getWeekOfDate(Date dt) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(dt);
		int weekDay = cal.get(Calendar.DAY_OF_WEEK) - 1;
		if (weekDay == 0) {
			weekDay = 7;
		}
		return weekDay;
	}

	public static LocalDateTime getNextHour() {
		return LocalDateTime.now().plus(1L, ChronoUnit.HOURS);
	}

	public static LocalDateTime getTomorrow() {
		return LocalDateTime.of(LocalDate.now().plusDays(1L), LocalTime.of(0, 0, 0, 0));
	}

	public static LocalDateTime getNextMonday() {
		return LocalDateTime.of(LocalDate.now().plusWeeks(1L).with(DayOfWeek.MONDAY), LocalTime.of(0, 0, 0, 0));
	}

	public static LocalDateTime getNextMonth1st() {
		return LocalDateTime.of(LocalDate.now().plusMonths(1L).withDayOfMonth(1), LocalTime.of(0, 0, 0, 0));
	}

	public static long calSpanSeconds(Date startDate, Date endDate) {
		long a = endDate.getTime();
		long b = startDate.getTime();
		return ((a - b) / 1000);
	}

	public static Date getEndOfDay(Date date) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.set(Calendar.HOUR_OF_DAY, 23);
		cal.set(Calendar.MINUTE, 59);
		cal.set(Calendar.SECOND, 59);
		cal.set(Calendar.MILLISECOND, 999);
		return cal.getTime();
	}

	public static Date getStartOfDay(Date date) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
		return cal.getTime();
	}

	public static Date getStartOfDay(Date date, int days) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.add(Calendar.DAY_OF_MONTH, days);
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
		return cal.getTime();
	}

	public static Date incMonth(Date date, int num) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.add(Calendar.MONTH, num);
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
		return cal.getTime();
	}

	/**
	 * 获取两个日期相差的月数
	 *
	 * @param startDate
	 *            较小的日期
	 * @param endDate
	 *            较大的日期
	 * @return 如果后者时间比前者大返回月数差 否则返回0
	 */
	public static int calSpanMonths(Date startDate, Date endDate) {
		Calendar endDateCal = Calendar.getInstance();
		Calendar startDateCal = Calendar.getInstance();
		endDateCal.setTime(endDate);
		startDateCal.setTime(startDate);
		if (endDateCal.getTimeInMillis() < startDateCal.getTimeInMillis())
			return 0;
		int endDateYear = endDateCal.get(Calendar.YEAR);
		int startDateYear = startDateCal.get(Calendar.YEAR);
		int endDateMonth = endDateCal.get(Calendar.MONTH);
		int startDateMonth = startDateCal.get(Calendar.MONTH);
		int endDateDay = endDateCal.get(Calendar.DAY_OF_MONTH);
		int startDateDay = startDateCal.get(Calendar.DAY_OF_MONTH);
		// 获取年的差值 假设 d1 = 2015-8-16 d2 = 2011-9-30
		int yearInterval = endDateYear - startDateYear;
		// 如果 d1的 月-日 小于 d2的 月-日 那么 yearInterval-- 这样就得到了相差的年数
		if (endDateMonth < startDateMonth || endDateMonth == startDateMonth && endDateDay < startDateDay) {
			yearInterval--;
		}
		// 获取月数差值
		int monthInterval = (endDateMonth + 12) - startDateMonth;
		if (endDateDay < startDateDay) {
			monthInterval--;
		}
		monthInterval %= 12;
		return yearInterval * 12 + monthInterval;
	}

	/**
	 * 获取固定间隔时刻集合
	 *
	 * @param start
	 *            开始时间
	 * @param end
	 *            结束时间
	 * @param interval
	 *            时间间隔(单位：分钟)
	 * @return
	 */
	public static List<String> getIntervalTimeList(String start, String end, int interval) {
		List<String> list = new ArrayList<>();
		try {
			SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
			Date startDate = sdf.parse(start);
			Date endDate = sdf.parse(end);
			while (startDate.getTime() <= endDate.getTime()) {
				String startDateStr = sdf.format(startDate);
				list.add(startDateStr);
				Calendar calendar = Calendar.getInstance();
				calendar.setTime(startDate);
				calendar.add(Calendar.MINUTE, interval);
				if (calendar.getTime().getTime() > endDate.getTime()) {
					if (!startDate.equals(endDate)) {
						String endDateStr = sdf.format(endDate);
						list.add(endDateStr);
					}
					startDate = calendar.getTime();
				} else {
					startDate = calendar.getTime();
				}

			}
		} catch (Exception e) {
		}
		return list;
	}

	/**
	 * 获取本月开始时间
	 *
	 * @return
	 */
	public static Date getStartTimeOfCurrMonth() {
		Calendar cal = Calendar.getInstance();
		cal.add(Calendar.MONTH, 0);
		cal.set(Calendar.DAY_OF_MONTH, 1);
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
		return cal.getTime();
	}

	public static Date getEndTimeOfCurrMonth() {
		Calendar cal = Calendar.getInstance();
		cal.add(Calendar.MONTH, 1);
		cal.set(Calendar.DAY_OF_MONTH, 0);
		cal.set(Calendar.HOUR_OF_DAY, 23);
		cal.set(Calendar.MINUTE, 59);
		cal.set(Calendar.SECOND, 59);
		cal.set(Calendar.MILLISECOND, 59);
		return cal.getTime();
	}

	public static Date getStartTimeOfMonth(Date date) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.set(Calendar.DAY_OF_MONTH, 1);
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
		return cal.getTime();
	}

	public static Date getEndTimeOfMonth(Date date) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.add(Calendar.MONTH, 1);
		cal.set(Calendar.DAY_OF_MONTH, 0);
		cal.set(Calendar.HOUR_OF_DAY, 23);
		cal.set(Calendar.MINUTE, 59);
		cal.set(Calendar.SECOND, 59);
		cal.set(Calendar.MILLISECOND, 59);
		return cal.getTime();
	}

	public static Date getStartTimeOfMonth(int year, int month) {
		Calendar cal = Calendar.getInstance();
		cal.set(Calendar.YEAR, year);
		cal.set(Calendar.MONTH, month - 1);
		cal.set(Calendar.DAY_OF_MONTH, 1);
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
		return cal.getTime();
	}

	public static Date getEndTimeOfMonth(int year, int month) {
		Calendar cal = Calendar.getInstance();
		cal.set(Calendar.YEAR, year);
		cal.set(Calendar.MONTH, month);
		cal.set(Calendar.DAY_OF_MONTH, 1);
		cal.set(Calendar.HOUR_OF_DAY, 23);
		cal.set(Calendar.MINUTE, 59);
		cal.set(Calendar.SECOND, 59);
		cal.set(Calendar.MILLISECOND, 999);
		cal.add(Calendar.DAY_OF_MONTH, -1);
		return cal.getTime();
	}

	/**
	 * 获取本周开始时间
	 *
	 * @return
	 */
	public static Date getStartTimeOfCurrWeek() {
		Date date = new Date();
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
		if (dayOfWeek == 1) {
			dayOfWeek += 7;
		}
		cal.add(Calendar.DATE, 2 - dayOfWeek);
		return getDayStartTime(cal.getTime());
	}

	public static Date getStartTimeOfWeek(Date date) {
		if (date == null) {
			return null;
		}
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
		if (dayOfWeek == 1) {
			dayOfWeek += 7;
		}
		cal.add(Calendar.DATE, 2 - dayOfWeek);
		return getDayStartTime(cal.getTime());
	}

	public static Date getDayStartTime(Date d) {
		Calendar calendar = Calendar.getInstance();
		if (null != d) {
			calendar.setTime(d);
		}
		calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 0,
				0, 0);
		calendar.set(Calendar.MILLISECOND, 0);
		return calendar.getTime();
	}

	/**
	 * 获取上月开始时间
	 *
	 * @return
	 */
	public static Date getStartTimeOfLastMonth() {
		Calendar cal = Calendar.getInstance();
		cal.add(Calendar.MONTH, -1);
		cal.set(Calendar.DAY_OF_MONTH, 1);
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
		return cal.getTime();
	}

	/**
	 * 获取上月结束时间
	 *
	 * @return
	 */
	public static Date getEndTimeOfLastMonth() {
		Calendar cal = Calendar.getInstance();
		cal.set(Calendar.DAY_OF_MONTH, 1);
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
		cal.add(Calendar.MILLISECOND, -1);
		return cal.getTime();
	}

	/**
	 * 获取本年开始时间
	 *
	 * @return
	 */
	public static Date getStartTimeOfCurrYear() {
		Calendar cal = Calendar.getInstance();
		cal.set(cal.get(Calendar.YEAR), 0, 1, 0, 0, 0);
		return cal.getTime();
	}

	/**
	 * 获取本年结束时间
	 *
	 * @return
	 */
	public static Date getEndTimeOfCurrYear() {
		Calendar cal = Calendar.getInstance();
		cal.set(cal.get(Calendar.YEAR), 11, 31, 23, 59, 59);
		return cal.getTime();
	}

	/**
	 * 获取去年开始时间
	 *
	 * @return
	 */
	public static Date getStartTimeOfLastYear() {
		Calendar cal = Calendar.getInstance();
		cal.set(cal.get(Calendar.YEAR) - 1, 0, 1, 0, 0, 0);
		return cal.getTime();
	}

	// 获取前num天的时间
	public static Date getStartDateOfLastDay() {
		Calendar cal = Calendar.getInstance();
		cal.add(Calendar.DAY_OF_MONTH, -1);
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
		return cal.getTime();
	}

	// 获取前一天结束的时间
	public static Date getEndDateOfLastDay() {
		// 获取当前时间
		Calendar cal = Calendar.getInstance();
		// 获取前一天时间
		cal.add(Calendar.DAY_OF_MONTH, -1);
		cal.set(Calendar.HOUR_OF_DAY, 23);
		cal.set(Calendar.MINUTE, 59);
		cal.set(Calendar.SECOND, 59);
		cal.set(Calendar.MILLISECOND, 0);
		return cal.getTime();
	}

	/**
	 * 获取去年结束时间
	 *
	 * @return
	 */
	public static Date getEndTimeOfLastYear() {
		Calendar cal = Calendar.getInstance();
		cal.set(cal.get(Calendar.YEAR) - 1, 11, 31, 23, 59, 59);
		return cal.getTime();
	}

	public static Date getStartTimeOfYear(int year) {
		Calendar cal = Calendar.getInstance();
		cal.set(year, 0, 1, 0, 0, 0);
		return cal.getTime();
	}

	public static Date getEndTimeOfYear(int year) {
		Calendar cal = Calendar.getInstance();
		cal.set(year, 11, 31, 23, 59, 59);
		return cal.getTime();
	}

	/**
	 * 两个日期相减之后的天数
	 *
	 * @param d1
	 * @param d2
	 * @return
	 */
	public static int minusDay(Date d1, Date d2) {
		long len = 1000 * 60 * 60 * 24;
		long dv = d1.getTime() - d2.getTime();

		return dv % len > 0 ? (int) (dv / len) + 1 : (int) (dv / len);
	}

	public static void main(String[] args) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		System.out.println(sdf.format(getStartTimeOfCurrMonth()));
		System.out.println(sdf.format(getStartTimeOfLastMonth()));
		System.out.println(sdf.format(getEndTimeOfLastMonth()));
		System.out.println(sdf.format(getStartTimeOfCurrYear()));
		System.out.println(sdf.format(getStartTimeOfLastYear()));
		System.out.println(sdf.format(getEndTimeOfLastYear()));
		System.out.println(sdf.format(getStartTimeOfCurrWeek()));
		System.out.println(sdf.format(getEndTimeOfMonth(parseDate("2020-10-31"))));
		System.out.println(sdf.format(getEndTimeOfCurrYear()));

		System.out.println(differentMinutesByMillisecond(new Date().getTime(), 1574680131876L));

	}

	/**
	 * 通过时间秒毫秒数判断两个时间的间隔
	 *
	 * @return
	 */
	public static int differentMinutesByMillisecond(Long dateTime1, Long dateTime2) {
		int minutes = (int) ((dateTime1 - dateTime2) / (60000));
		return minutes;
	}

	/**
	 * 获取两个时间节点之间的月份列表
	 **/
	public static List<Integer> getMonthBetween(String minDate, String maxDate) {
		ArrayList<Integer> result = new ArrayList<Integer>();
		try {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");// 格式化为年月

			Calendar min = Calendar.getInstance();
			Calendar max = Calendar.getInstance();
			min.setTime(sdf.parse(minDate));
			min.set(min.get(Calendar.YEAR), min.get(Calendar.MONTH), 1);

			max.setTime(sdf.parse(maxDate));
			max.set(max.get(Calendar.YEAR), max.get(Calendar.MONTH), 2);

			Calendar curr = min;
			while (curr.before(max)) {
				result.add(Integer.parseInt(sdf.format(curr.getTime()).replace("-", "")));
				curr.add(Calendar.MONTH, 1);
			}
		} catch (ParseException e) {
			e.printStackTrace();
		}

		return result;
	}
}
